package com.cn.shiro.zy.shiro.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.cn.shiro.zy.shiro.realm.MyRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author zhangyi
 * @date 2018/12/11 18:04
 */
@Configuration
public class ShiroConfig {


    @Bean(name = "sessionManager")
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //设置过期时间 一天
        sessionManager.setGlobalSessionTimeout(1 * 60 * 60 * 24);
        sessionManager.setSessionValidationSchedulerEnabled(true);

        //如果开启shiroredis缓存，则将shiro session存到redis里
/*        if (shiroRedisOpen) {
            sessionManager.setSessionDAO(redisShiroSessionDAO);
        }*/
        return sessionManager;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager(@Qualifier("myRealm") MyRealm myRealm
            , @Qualifier("sessionManager") SessionManager sessionManager) {
        DefaultWebSecurityManager ds = new DefaultWebSecurityManager();
        //设置过期时间
        ds.setSessionManager(sessionManager);
        ds.setRealm(myRealm);
        return ds;
    }

    /**
     * 只是创建一个ShiroFilterFactory是错误的
     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager
     *
     * @param defaultSecurityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultSecurityManager) {
        ShiroFilterFactoryBean sf = new ShiroFilterFactoryBean();
        //设置安全管理器
        sf.setSecurityManager(defaultSecurityManager);
        sf.setLoginUrl("/login");
        sf.setUnauthorizedUrl("/non");
        sf.setSuccessUrl("/index");
        /**
         * 自定义过滤器
         * anon: 所有url都都可以匿名访问
         * authc:所有url都必须认证通过才可以访问;
         * user: 只有实现了remberme的操作才能访问
         * perms: 必须得到资源权限才能访问
         * role: 必须得到角色权限的时候才能访问
         */
        Map<String, String> china = new LinkedHashMap<>();
        china.put("/index", "authc");
        china.put("/update", "authc");
        china.put("/non", "authc");
        china.put("/info","authc");
        //这里可以自定义权限授权，拼装字符串
        //...
//        china.put("/add","perms[user:add]");
//        china.put("/update","perms[user:update]");
//      过滤链定义，从上向下顺序执行，一般将 /**放在最为下边
        china.put("/**", "anon");
        sf.setFilterChainDefinitionMap(china);
        return sf;
    }

    @Bean(name = "myRealm")
    public MyRealm getRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher hashedCredentialsMatcher) {
        MyRealm myRealm = new MyRealm();
//        //设置自定义加密
        myRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return myRealm;
    }

    /**
     * 配置可以在thymeleaf可以使用标签
     *
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     * 所以我们需要修改下doGetAuthenticationInfo中的代码;
     * ）
     *
     * @return
     */
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        //注入ehcache 缓存
        HashedCredentialsMatcher hashedCredentialsMatcher = new MyHashedCredent();
        //使用指定的散列算法
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        //几次散列？
        hashedCredentialsMatcher.setHashIterations(3);
        //设置16进制编码
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }
/*
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager em = new EhCacheManager();
        //将ehcacheManager转换成shiro包装后的ehcacheManager对象
        em.setCacheManagerConfigFile("classpath:/ehcache.xml");
        return em;
    }*/

    /**
     * 解决@RequiresPermissions("user:update")注解无效
     * 把shiro生命周期交给spring boot管理
     *
     * @return
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager defaultSecurityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(defaultSecurityManager);
        return advisor;
    }


}
